//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_CIRCLE_H
#define _UXS_CIRCLE_H

#pragma once

#include "TRect.h"
#include "TLine.h"

namespace UX_STL
{
namespace UXMath
{

	//
	// Circle
	//

	template <typename T>
	struct TCircle
	{
	// types
	public:
		typedef TCircle< T >	Self;
		typedef TVec< T, 2 >	vec_t;
		typedef TRect< T >		rect_t;
		typedef TLine< vec_t >	line_t;


	// variables
	private:
		vec_t	_center;
		T		_radius;


	// methods
	public:
		TCircle () : _radius(0) {}
		TCircle (T radius) : _radius(radius) {}
		TCircle (const vec_t &center, T radius) : _radius(radius), _center(center) {}

		Self &	Move (const vec_t &delta);
		Self &	SetCenter (const vec_t &center);

		Self &	AddToRadius (T radius);
		Self &	SetRadius (T radius);

		rect_t			ToRect ()			const;
		vec_t const &	Center ()			const	{ return _center; }
		vec_t &			Center ()					{ return _center; }
		T const &		Radius ()			const	{ return _radius; }
		T &				Radius ()					{ return _radius; }
		T				RadiusSqr ()		const	{ return _radius * _radius; }
		T				Length ()			const	{ return T(2) * Pi<T>() * Radius(); }
		T				ArcLength (T angle)	const	{ return angle * Radius(); }
		T				Square ()			const	{ return Pi<T>() * Square( Radius() ); }

		line_t			GetChord (T startAngle, T endAngle)	const;
		vec_t			GetPoint (T angle)					const;
		T				GetAngle (const vec_t &point)		const;
		T				AngleFromArcLength (T len)			const	{ return len / Radius(); }
		T				AngleFromChordLength (T len)		const	{ return T(2) * ASin( len / ( T(2) * Radius() ) ); }
		
		vec_t			GetXfromY (T y) const;
		vec_t			GetYfromX (T x) const;

		bool IsInnerPoint (const vec_t &vPoint)		const;
		bool IsInnerLine (const line_t &sLine)		const;
		bool IsInnerRect (const rect_t &sRect)		const;
		bool IsInnerCircle (const Self &sCircle)	const;

		bool IntersectLine (const line_t &sLine)	const;
		bool IntersectRect (const rect_t &sRect)	const;
		bool IntersectCircle (const Self &sCircle)	const;
	};



	
	template <typename T>
	inline TCircle<T> &  TCircle<T>::Move (const vec_t &delta)
	{
		_center += delta;
		return *this;
	}
	

	template <typename T>
	inline TCircle<T> &  TCircle<T>::SetCenter (const vec_t &center)
	{
		_center = center;
		return *this;
	}
	

	template <typename T>
	inline TCircle<T> &  TCircle<T>::AddToRadius (T radius)
	{
		_radius += radius;
		return *this;
	}
	

	template <typename T>
	inline TCircle<T> &  TCircle<T>::SetRadius (T radius)
	{
		_radius = radius;
		return *this;
	}
	

	template <typename T>
	inline TRect<T>  TCircle<T>::ToRect () const
	{
		rect_t	r( _center, _center );
		r.LeftBottom() += _radius;
		r.RightTop()   += _radius;
	}
	

	template <typename T>
	inline TVec<T,2>  TCircle<T>::GetPoint (T angle) const
	{
		return _center + _radius * SinCos( angle ).yx();
	}
	

	template <typename T>
	inline T TCircle<T>::GetAngle (const vec_t &point) const
	{
		//const vec_t	v = point - _center;
		//const T		d = v.Length();
		const vec_t	sc = (point - _center).Normalized(); //v / d;
		return ATan( sc.y, sc.x );
	}
	

	template <typename T>
	inline TVec<T,2>  TCircle<T>::GetXfromY (const T y) const
	{
		// (x-cx)^2 + (y-cy)^2 = R^2
		const T	x = Sqrt( Square( _radius ) - Square( y - _center.y ) );
		return _center.x + vec_t( x, -x );
	}

	
	template <typename T>
	inline TVec<T,2>  TCircle<T>::GetYfromX (const T x) const
	{
		const T	y = Sqrt( Square( _radius ) - Square( x - _center.x ) );
		return _center.y + vec_t( y, -y );
	}


	template <typename T>
	inline TLine< TVec<T,2> >  TCircle<T>::GetChord (T startAngle, T endAngle) const
	{
		return line_t( GetPoint( startAngle ), GetPoint( endAngle ) );
	}


	template <typename T>
	inline bool TCircle<T>::IsInnerPoint (const vec_t &vPoint) const
	{
		return _center.DistanceSqr( vPoint ) <= RadiusSqr();
	}
	

	template <typename T>
	inline bool TCircle<T>::IsInnerLine (const line_t &sLine) const
	{
		return IsInnerPoint( sLine.Begin() ) and IsInnerPoint( sLine.End() );
	}
	

	template <typename T>
	inline bool TCircle<T>::IsInnerRect (const rect_t &sRect) const
	{
		return IsInnerPoint( sRect.LeftBottom() ) and IsInnerPoint( sRect.RightTop() );
	}
	

	template <typename T>
	inline bool TCircle<T>::IsInnerCircle (const Self &sCircle) const
	{
		return	_radius >= sCircle.Radius() and
				_center.DistanceSqr( sCircle.Center() ) + sCircle.RadiusSqr() <= RadiusSqr();
	}
	

	template <typename T>
	inline bool TCircle<T>::IntersectLine (const line_t &sLine) const
	{
		TODO( "IntersectLine" );
		return sLine.IntersectRect( ToRect() );
	}
		
	
	template <typename T>
	inline bool TCircle<T>::IntersectRect (const rect_t &sRect) const
	{
		return sRect.IntersectRect( ToRect() );
	}
		
	
	template <typename T>
	inline bool TCircle<T>::IntersectCircle (const Self &sCircle) const
	{
		return _center.DistanceSqr( sCircle.Center() ) - sCircle.RadiusSqr() <= RadiusSqr();
	}


//-------------------------------------------------------------------

}	// UXMath
}	// UX_STL

#endif	// _UXS_CIRCLE_H
